//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler execution subsystem, fast (release) version
// FILE:            xruntime2.cpp
// AUTHOR:          Vladimir Gumenuk
// DATE:            23-Sep-2015
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"
#include "xruntime.h"
#include "xobject.h"
#include "xniobject.h"
#include "xbuildin.h"
#include "xprimimpl.h"
#include "xcode.h"
#include "BuildinObjectInfo.h"
#include "listImpl.h"
#include "XortStringImpl.h"
#include "XortElementImpl.h"

void XRuntime::do_fast_addrof( const InstructionData& primData )
{
    // Instruction is redundant. There is no reason to implement it.
}

void XRuntime::do_fast_load( const InstructionData& primData )
{
    byte bCmdType = primData.m_bTypeAddr & 0xF0;

    switch( primData.m_bTypeAddr & 0x0F )
    {
    case a_c:
        {
            const_cast<InstructionData&>( primData ).m_Value.bAccess = usr_VarRW;
            m_Stack.push( primData.m_Value ); 
            break;
        }
    case a_m: 
        {
            XortElement x = m_Data.get( primData.m_Value._u4 );
            m_Stack.push( x );
            break;
        }
    case a_s:
        {
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            XortElement x = m_Stack.get( (dword)iIdx );
            m_Stack.push( x );
            break;
        }
    case a_indm: 
        {
            XortElement x = m_Stack.pop();
            XortElement m = m_Data.get( x._u4 );
            m.bAccess = usr_VarRW; //-change the access type, as it is now on arith stack
            m_Stack.push( m );
            break;
        }
    case a_inds:
        {
            XortElement x = m_Stack.pop();
            int iIdx = (int)m_dwStackBase + x._s2;
            XortElement s = m_Stack.get( (dword)iIdx );
            s.bAccess = usr_VarRW;
            m_Stack.push( s );
            break;
        }
    case a_ti:
        {
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement x;
            pObj->Get( primData.m_Value._u2, x );
            x.bAccess = usr_VarRW;
            m_Stack.push( x );
            break;
        }
    }
}   

void XRuntime::do_fast_mov( const InstructionData& primData )
{
    byte bCmdType = primData.m_bTypeAddr & 0xF0;
    byte bAddr    = primData.m_bTypeAddr & 0x0F;
    int iOffset;

    switch( bAddr )
    {
    case a_cs:    // mov.cs.T   S[#] = c
        {
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            XortElement& v1 = m_Stack.get( (dword)iOffset );
            v1 = primData.m_Value2;
            break;
        }
    case a_cm:    // mov.cm.T   M[#] = c
        {
            XortElement& v1 = m_Data.get( primData.m_Value._u4 );
            v1 = primData.m_Value2;
            break;
        }
    case a_ms:    // mov.ms.T   S[#] = M[#]
        {
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            XortElement& v1 = m_Stack.get( (dword)iOffset );
            XortElement& v2 = m_Data.get( primData.m_Value2._u4 );
            v1 = v2;
            break;
        }
    case a_sm:    // mov.sm.T   M[#] = S[#]
        {
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            XortElement& v2 = m_Stack.get( (dword)iOffset );
            XortElement& v1 = m_Data.get( primData.m_Value._u4 );
            v1 = v2;
            break;
        }
    case a_ss:    // mov.ss.T   S[#] = S[#]
        {
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            XortElement& v2 = m_Stack.get( (dword)iOffset );
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            XortElement& v1 = m_Stack.get( (dword)iOffset );
            v1 = v2;
            break;
        }
    case a_mm:    // mov.mm.T   M[#] = M[#]
        {
            XortElement& v1 = m_Data.get( primData.m_Value._u4 );
            XortElement& v2 = m_Data.get( primData.m_Value2._u4 );
            v1 = v2;
            break;
        }
    }
}

void XRuntime::do_fast_store( const InstructionData& primData )
{
    byte bCmdType = primData.m_bTypeAddr & 0xF0;

    switch( primData.m_bTypeAddr & 0x0F )
    {
    case a_m: 
        {
            XortElement x = m_Stack.pop();
            XortElement& m = m_Data.get( primData.m_Value._u4 );
            m = x;
            break;
        }
    case a_s:
        {
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            XortElement& x = m_Stack.get( (dword)iIdx );
            XortElement t = m_Stack.pop();
            x = t;
            break;
        }
    case a_indm: 
        {
            XortElement x = m_Stack.pop();
            XortElement& m = m_Data.get( x._u4 );
            XortElement t = m_Stack.pop();
            m = t;
            break;
        }
    case a_inds:
        {
            XortElement x = m_Stack.pop();
            int iIdx = (int)m_dwStackBase + x._s2;
            XortElement& s = m_Stack.get( (dword)iIdx );
            XortElement t = m_Stack.pop();
            s = t;
            break;
        }
    case a_ti:
        {
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement x = m_Stack.pop();
            pObj->Put( primData.m_Value._u2, x );
            break;
        }
    }
}

void XRuntime::do_fast_drop( const InstructionData& primData )
{
    XortElement x = m_Stack.pop();
}

void XRuntime::do_fast_dup( const InstructionData& primData )
{
    XortElement x = m_Stack.top();
    m_Stack.push( x );
}

void XRuntime::do_fast_swap( const InstructionData& primData )
{
    XortElement x = m_Stack.top();
    dword dwCount = m_Stack.count();
    m_Stack.put( dwCount-1, m_Stack.get( dwCount-2 ) );
    m_Stack.put( dwCount-2, x );
}

void XRuntime::do_fast_arith( const InstructionData& primData, _lopfn_t *pfn )
{ 
    XortElement v1, v2, vRes;
    int iOffset;
    xobject *pObj;

    byte bCmdType = primData.m_bTypeAddr & 0xF0;
    byte bAddr    = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0:     // add.T	v1, v2 -> v1 + v2
        {
            v2 = m_Stack.pop();
            v1 = m_Stack.pop();
            pfn( v1, v2, vRes );
            m_Stack.push( vRes );
            break;
        }   
    case a_c:   // add.c.T	v1 -> v1 + c
        {
            v2 = primData.m_Value;
            v1 = m_Stack.pop();
            pfn( v1, v2, vRes );
            m_Stack.push( vRes );
            break;
        }
    case a_m:   // add.m.T	v1 -> v1 + M[#]
        {
            v1 = m_Stack.pop();
            v2 = m_Data.get( primData.m_Value._u4 );
            pfn( v1, v2, vRes );
            m_Stack.push( vRes );
            break;
        }
    case a_s:   // add.s.T	v1 -> v1 + S[#]
        {
            v1 = m_Stack.pop();
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            v2 = m_Stack.get( (dword)iOffset );
            pfn( v1, v2, vRes );
            m_Stack.push( vRes );
            break;
        }
    case a_indm: break;
    case a_inds: break;
    case a_cs:  // add.cs.T	S[#] += c
        {
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            v1 = m_Stack.get( (dword)iOffset );
            v2 = primData.m_Value2;
            pfn( v1, v2, vRes );
            m_Stack.put( iOffset, vRes );
            break;
        }
    case a_cm:  // add.cm.T	M[#] += c
        {
            v1 = m_Data.get( primData.m_Value._u4 );
            v2 = primData.m_Value2;
            pfn( v1, v2, vRes );
            m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    case a_ms:  // add.ms.T	S[#] += M[#]
        {
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            v1 = m_Stack.get( (dword)iOffset );
            v2 = m_Data.get( primData.m_Value2._u4 );
            pfn( v1, v2, vRes );
            m_Stack.put( (dword)iOffset, vRes );
            break;
        }
    case a_sm:  // add.sm.T	M[#] += S[#]
        {
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            v2 = m_Stack.get( (dword)iOffset );
            v1 = m_Data.get( primData.m_Value._u4 );
            pfn( v1, v2, vRes );
            m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    case a_ss:  // add.ss.T	S[#] += S[#]
        {
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            v2 = m_Stack.get( (dword)iOffset );
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            v1 = m_Stack.get( (dword)iOffset );
            pfn( v1, v2, vRes );
            m_Stack.put( (dword)iOffset, vRes );
            break;
        }
    case a_mm:  // add.mm.T	M[#] += M[#]
        {
            v1 = m_Data.get( primData.m_Value._u4 );
            v2 = m_Data.get( primData.m_Value2._u4 );
            pfn( v1, v2, vRes );
            m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    case a_ma:  break;
    case a_sa:  break;
    case a_ta:  break;
    case a_ti:  // v1 -> v1 + T[#] 
        {
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            pObj = (xobject *)sysFr._ti;
            pObj->Get( primData.m_Value._u2, v2 );
            v1 = m_Stack.pop();
            pfn( v1, v2, vRes );
            m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    }
}

void XRuntime::do_fast_unary_prim( const InstructionData& primData, _opfn_t *pfn )
{
    byte bCmdType = primData.m_bTypeAddr & 0xF0;

    switch( primData.m_bTypeAddr & 0x0F )
    {
    case t_v:
        {
            XortElement& x = m_Stack.top();
            pfn( x );
            break;
        }
    case a_m:
        {
            XortElement& x = m_Data.get( primData.m_Value._u4 );
            pfn( x );
            break;
        }
    case a_s:
        {
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            XortElement& x = m_Stack.get( (dword)iIdx );
            pfn( x );
            break;
        }
    case a_ti:
        {
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement v;
            pObj->Get( primData.m_Value._u2, v );
            pfn( v );
            pObj->Put( primData.m_Value._u2, v );
            break;
        }
    }
}

void XRuntime::do_fast_nz( const InstructionData& primData )
{
    XortElement x = m_Stack.pop();
    XortElement vRes;
    const_nz( x, vRes );
    m_Stack.push( vRes );
}

void XRuntime::do_fast_logical_op( const InstructionData& primData, _lopfn_t *pfn )
{   
    XortElement v2 = m_Stack.pop();
    XortElement v1 = m_Stack.pop();
    XortElement vRes;
    pfn( v1, v2, vRes );
    m_Stack.push( vRes );
}

void XRuntime::do_fast_convert( const InstructionData& primData )
{
    XortElement& x = m_Stack.top();
    byte bSrcType = ( primData.m_bTypeAddr & 0x0F ) << 4;
    byte bDstType = primData.m_bTypeAddr & 0xF0;

    XortElement n;
    x_convert_type( bDstType, n, x );
    x.bType = bDstType;
    x._u8 = n._u8;
}

void XRuntime::do_fast_goto( const InstructionData& primData )
{
    int iOffset = 0;

    switch( primData.m_bTypeAddr & 0xF0 )
    { 
    case t_s1: iOffset = primData.m_Value._s1; break;
    case t_s2: iOffset = primData.m_Value._s2; break;
    case t_s4: iOffset = primData.m_Value._s4; break;
    }

    applyOffsetIP( iOffset );
}

void XRuntime::do_fast_ifz_nz( const InstructionData& primData, _copfnifx *pfn )
{
    int iResult = 0;
    byte bCmdType = primData.m_bTypeAddr & 0xF0;
    byte bAddr    = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0: // means operate on stack: value != 0 -> ...
        {
            XortElement x = m_Stack.pop();
            pfn( x, iResult );
            if( iResult ) applyOffsetIP( primData.m_Value._s2 );
            break;
        }
    case a_ma:  // M[#] != 0
        {
            XortElement& x = m_Data.get( primData.m_Value._u4 );
            pfn( x, iResult );
            if( iResult ) applyOffsetIP( primData.m_Value2._s2 );
            break;
        }
    case a_sa:  // S[#] != 0
        {
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            XortElement& x = m_Stack.get( (dword)iIdx );
            pfn( x, iResult );
            if( iResult ) applyOffsetIP( primData.m_Value2._s2 );
            break;
        }
    case a_ta:  // T[#] != 0 - not implemented in the compiler yet
        {
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement v1;
            pObj->Get( primData.m_Value._u2, v1 );
            pfn( v1, iResult );
            if( iResult ) applyOffsetIP( primData.m_Value2._s2 );
        
            break;
        }
    }
}

void XRuntime::do_fast_if_xx( const InstructionData& primData, _lopfn_t *pfn )
{ 
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;
    XortElement v1, v2, vRes;
    int iOffset, iIdx;

    switch( bAddr )
    {
    case 0: // means operate on stack:      ifeq.T   v1, v2 == -> ...
        {
            iOffset = primData.m_Value._s2;
            v2 = m_Stack.pop();
            v1 = m_Stack.pop();
            break;
        }
    case a_ma:  // ifeq.ma.T    v1 == M[#] -> ...
        {
            iOffset = primData.m_Value2._s2;
            v1 = m_Stack.pop();
            v2 = m_Data.get( primData.m_Value._u4 );
            break;
        }
    case a_sa:  // ifeq.sa.T    v1 == S[#] -> ...
        {
            iOffset = primData.m_Value2._s2;
            iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            v1 = m_Stack.pop();
            v2 = m_Stack.get( (dword)iIdx );
            break;
        }
    case a_ta:  // ifeq.ta.T    v1 == T[#] -> ...
        {
            v1 = m_Stack.pop();
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            xobject *pObj = (xobject *)sysFr._ti;
            pObj->Get( primData.m_Value._u2, v2 );
            iOffset = primData.m_Value2._s2;
            break;
        }
    }

    pfn( v1, v2, vRes );
    if( vRes._s4 ) applyOffsetIP( iOffset );
}

void XRuntime::do_fast_calli( const InstructionData& primData )
{
    symbolref pFunc = m_Functions.get( primData.m_Value._u4 );
    dword dwFuncRetType = pFunc->m_dwType >= t_p ? t_p : pFunc->m_dwType; // align types

    XortElement x;
    x.bAccess = sys_Frame;
    if( pFunc->m_dwFlags & f_unspecnumargs ) { // apply the actual number of arguments for unspecified number of args
        XortElement argNo = m_Stack.pop();     // trick: we pop out the informational argument with the number of args
        x.bType = argNo._u1;                   // and put the number of arguments into system frame
    } else {
        x.bType = pFunc->m_listMembers.size() - 1; // set number of arguments, skip localScope marker
    }

    x._ti = 0;
    x._asp = m_dwStackBase;             // save old stack base
    m_dwStackBase = m_Stack.push( x );  // create system frame

    // save current IP
    x.bType = t_u4; x.bAccess = sys_Frame; x._u4 = m_dwIP;
    m_RetStack.push( x );
   
    Exec( *pFunc ); 
}

void XRuntime::do_fast_call( const InstructionData& primData )
{
    XortElement addr = m_Stack.pop();

    symbolref pFunc = m_Functions.get( addr._u4 );

    XortElement x;
    x.bAccess = sys_Frame;
    if( pFunc->m_dwFlags & f_unspecnumargs ) { // apply the actual number of arguments for unspecified number of args
        XortElement argNo = m_Stack.pop();     // trick: we pop out the informational argument with the number of args
        x.bType = argNo._u1;                   // and put the number of arguments into system frame
    } else {
        x.bType = pFunc->m_listMembers.size() - 1; // set number of arguments, skip localScope marker
    }

    x._ti = 0;
    x._asp = m_dwStackBase;             // save old stack base
    m_dwStackBase = m_Stack.push( x );  // create system frame

    // save current IP
    x.bType = t_u4; x.bAccess = sys_Frame; x._u4 = m_dwIP;
    m_RetStack.push( x );

    Exec( *pFunc ); 
}

void XRuntime::do_fast_ret( const InstructionData& primData )
{
    XortElement x;
    if( primData.m_bTypeAddr != t_v ) x = m_Stack.pop();

    // cleanup the stack till system frame
    int bBrake = FALSE;
    dword dwArgsCount = 0;
    do
    {
         XortElement xClean = m_Stack.pop();
         if( xClean.bAccess & sys_Frame ) {
             m_dwStackBase = xClean._asp;
             dwArgsCount = xClean.bType;   
             bBrake = TRUE;
         }
         xClean.Clear();
    } while( !bBrake );

    // remove arguments
    while( dwArgsCount ) {
        XortElement xClean = m_Stack.pop();
        xClean.Clear();
        dwArgsCount--;
    }

    if( primData.m_bTypeAddr != t_v ) m_Stack.push( x );

    XortElement retIP = m_RetStack.pop(); // restore IP
    m_dwIP = retIP._u4;
}

void XRuntime::do_fast_new( const InstructionData& primData )
{
    //byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;
    dword dwObjectType = 0;

    switch( bAddr )
    {
    case 0:
        {
            XortElement x = m_Stack.pop();
            dwObjectType = x._u4;
            break;
        }
    case a_c:
        {
            dwObjectType = primData.m_Value._u4;
            break;
        }
    }

    SymbolRef targetType = FindType( *m_pSymList, dwObjectType );

    XortElement x;
    createXObject( targetType, NULL, &x._p );

    x.bType   = t_p;
    x.bAccess = ( targetType.m_dwFlags & f_const ) ? usr_VarR : usr_VarRW; // setup constant flag

    m_Stack.push( x );
}

void XRuntime::do_fast_get( const InstructionData& primData )
{
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0: // ref, index -> value
        {
            XortElement idx = m_Stack.pop();
            XortElement refObj = m_Stack.pop();
            XortElement val;
            refObj._p->Get( idx._u2, val );
            m_Stack.push( val );
            break;
        }
    case a_ti: // ... -> value
        {
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement v;
            pObj->Get( primData.m_Value._u2, v );
            m_Stack.push( v );
            break;
        }
    }
}

void XRuntime::do_fast_put( const InstructionData& primData )
{
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0: // put.T    value, ref, index -> ...
        {
            XortElement idx = m_Stack.pop();
            XortElement refObj = m_Stack.pop();
            XortElement val = m_Stack.pop();
            refObj._p->Put( idx._u2, val );
            break;
        }
    case a_ti: // put.ti.T  value -> ...
        {
            XortElement v = m_Stack.pop();
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            xobject *pObj = (xobject *)sysFr._ti;
            pObj->Put( primData.m_Value._u2, v );
            break;
        }
    }
}

void XRuntime::do_fast_invoke( const InstructionData& primData )
{
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;
    dword dwProcIdx;
    xobject *pObj;

    switch( bAddr )
    {
    case 0: // invoke.T [arg1, arg2, ...argN,] ref, index -> (result)
        {
            XortElement idx = m_Stack.pop();
            XortElement refObj = m_Stack.pop();
            dwProcIdx = idx._u2;
            pObj = refObj._p; pObj->AddRef();
            break;
        }
    case a_ti: // invoke.ti.T   [arg1, arg2, ...argN] -> (result)
        {
            dwProcIdx = primData.m_Value._u2;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            pObj = (xobject *)sysFr._ti; pObj->AddRef();
            break;
        }
    }

    symbolref pMethod = (symbolref)pObj->get_Method( dwProcIdx );

    XortElement xSys; 
    xSys.bAccess = sys_Frame;
    
    if( pMethod->m_dwFlags & f_unspecnumargs ) { // apply the actual number of arguments for unspecified number of args
        XortElement argNo = m_Stack.pop();       // trick: we pop out the informational argument with the number of args
        xSys.bType = argNo._u1;                  // and put the number of arguments into system frame
    } else {
        xSys.bType = pMethod->m_listMembers.size() - 1; // set number of arguments, skip localScope marker
    }

    xSys._ti = (dword)pObj;                // set this pointer
    xSys._asp = m_dwStackBase;             // save old stack base
    m_dwStackBase = m_Stack.push( xSys );  // create system frame
    
    xSys.bType = t_u4; xSys.bAccess = sys_Frame; xSys._u4 = m_dwIP;
    m_RetStack.push( xSys );               // save current IP
    pObj->Invoke( dwProcIdx, this );      // invoke object method
    pObj->Release();
}

void XRuntime::do_fast_gettype( const InstructionData& primData )
{
    XortElement refObj = m_Stack.pop();
    XortElement x; x.bType = t_u4; x.bAccess = usr_VarRW;
    x._u4 = refObj._p->GetType();
    m_Stack.push( x );
}

void XRuntime::do_fast_enter( const InstructionData& primData )
{
    XortElement x;
    x.bType     = 0xFF;     // reserved
    x.bAccess   = sys_Scope;// marker
    x._ti       = 0;
    x._asp      = 0;        // install exception handler here!
    m_Stack.push( x );      // create system scope frame
}

void XRuntime::do_fast_leave( const InstructionData& primData )
{
    int bBrake = FALSE;
    do  // cleanup the stack till system scope frame
    {
        XortElement xClean = m_Stack.pop();
        if( xClean.bAccess & sys_Scope ) bBrake = TRUE;
        xClean.Clear();
    } while( !bBrake );
}

void XRuntime::do_fast_nop( const InstructionData& primData )
{ 
    // do nothing :)
}

void XRuntime::do_fast_dbgbreak( const InstructionData& primData )
{
    // do nothig
}

void XRuntime::do_fast_pack( const InstructionData& primData )
{
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    XortElement xObj = m_Stack.pop();

    xobject *pObj = (xobject *)xObj._p;
    dword dwType = pObj->GetType();

    XObject *pByteArray = NULL;

    pObj->Pack( (void**)&pByteArray );

    xObj.Clear();
    xObj.bAccess = usr_VarRW;
    xObj.bType = t_p;
    xObj.SetValue( pByteArray );
    m_Stack.push( xObj );
}

void XRuntime::do_fast_upack( const InstructionData& primData )
{
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    XortElement& xObj = m_Stack.top();
    xobject *pObj = (xobject *)xObj._p;
    dword dwType = pObj->GetType();
    // Instruction is redundant. Do only basic checks here. The actual unpacking is done inside XNI object
}
